﻿using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Xml.Linq;

using Windows.ApplicationModel.Activation;
using Windows.Storage;
using Windows.UI.Core;
using Windows.UI.Xaml.Controls;
using Windows.Storage.Streams;
using Windows.ApplicationModel.DataTransfer;
using Windows.UI.Xaml.Media;
using Windows.UI;
using Windows.UI.Xaml.Navigation;

using SeriesManager.Model;
using System.Windows.Input;
using WinRTFramework.Interfaces.Contracts.Sharing;
using WinRTFramework.Common;
using WinRTFramework.Interfaces.Contracts.Settings.ViewModel;
using WinRTFramework.Interfaces.Contracts.Settings;

namespace SeriesManager.ViewModel
{
    public sealed class FrameViewModel : ViewModelBase, ISupportSharingSourceContract, IRequireSettingService
    {
        #region Properties

        private bool searchBarIsOpen;
        private bool navigationBarCanOpen;
        private object background;
        private FrameState state;
        private string searchQuery;

        public bool NavigationBarCanOpen
        {
            get
            {
                return this.navigationBarCanOpen;
            }
            private set
            {
                base.SetProperty<bool>(ref this.navigationBarCanOpen, value);
            }
        }

        public object Background
        {
            get
            {
                return this.background;
            }
            private set
            {
                base.SetProperty<object>(ref this.background, value);
            }
        }

        public AppX Model 
        { 
            get; 
            private set; 
        }

        public string SearchQuery
        {
            get
            {
                return this.searchQuery;
            }
            set
            {
                base.SetProperty(ref this.searchQuery, value);
                this.SearchCommand.NotifyCanExecuteChanged();
            }
        }

        public bool SearchBarIsOpen
        {
            get 
            { 
                return this.searchBarIsOpen; 
            }
            set 
            {
                base.SetProperty<bool>(ref this.searchBarIsOpen, value); 
            }
        }

        public ICommand NavigatedCommand
        {
            get;
            private set;
        }

        public ICommand HomeCommand
        {
            get;
            private set;
        }

        public DelegateCommand<SearchBoxQuerySubmittedEventArgs> SearchCommand
        {
            get;
            private set;
        }

        public ICommand SearchBarCommand
        {
            get;
            private set;
        }

        public ICommand SettingsCommand
        {
            get;
            private set;
        }

        public DelegateCommand<ItemClickEventArgs> AirDayCommand
        {
            get;
            private set;
        }

        public DelegateCommand<ItemClickEventArgs> AirWeekCommand
        {
            get;
            private set;
        }

        public DelegateCommand<ItemClickEventArgs> AirMonthCommand
        {
            get;
            private set;
        }

        public DelegateCommand<ItemClickEventArgs> AirYearCommand
        {
            get;
            private set;
        }

        #endregion

        public FrameViewModel()
        {
            this.Model = AppX.Instance;
            this.Model.PropertyChanged += Model_PropertyChanged;

            this.NavigatedCommand = new DelegateCommand<NavigationEventArgs>(OnNavigatedExecuted);
            this.HomeCommand = new DelegateCommand(() => { base.NavigationService.Navigate<SubscriptionViewModel>(); });
            this.SearchCommand = new DelegateCommand<SearchBoxQuerySubmittedEventArgs>(OnSearchExecuted, OnSearchCanExecute);
            this.SearchBarCommand = new DelegateCommand<ItemClickEventArgs>(OnSearchBarExecuted);
            this.SettingsCommand = new DelegateCommand<ItemClickEventArgs>(OnSettingsExecuted);
            this.AirDayCommand = new DelegateCommand<ItemClickEventArgs>(OnAirDayExecuted, OnAirDayCanExecute);
            this.AirWeekCommand = new DelegateCommand<ItemClickEventArgs>(OnAirWeekExecuted, OnAirWeekCanExecute);
            this.AirMonthCommand = new DelegateCommand<ItemClickEventArgs>(OnAirMonthExecuted, OnAirMonthCanExecute);
            this.AirYearCommand = new DelegateCommand<ItemClickEventArgs>(OnAirYearExecuted, OnAirYearCanExecute);
        }

        #region DelegateProperties

        private void OnSearchExecuted(SearchBoxQuerySubmittedEventArgs args)
        {
            base.NavigationService.Navigate<SearchViewModel>(this.SearchQuery);
        }

        private bool OnSearchCanExecute(SearchBoxQuerySubmittedEventArgs args)
        {
            return !string.IsNullOrWhiteSpace(this.SearchQuery);
        }

        private void OnSettingsExecuted(ItemClickEventArgs args)
        {
            base.NavigationBarIsOpen = false;
            this.SettingService.ShowIndependent<SettingsViewModel>();
        }

        private void OnNavigatedExecuted(NavigationEventArgs args)
        {
            var viewModel = base.NavigationService.CurrentViewModelType;
            if (viewModel != null)
            {
                if (viewModel == typeof(SubscriptionViewModel) || viewModel == typeof(SearchViewModel))
                {
                    SwitchState(FrameState.Entrance);
                }
                else if (viewModel == typeof(AirViewModel) && args != null && args.Parameter != null && (int)args.Parameter != 0)
                {
                    SwitchState(FrameState.Entrance);
                }
                else
                {
                    SwitchState(FrameState.Series);
                }
            }

            this.SearchBarIsOpen = false;
            base.NavigationBarIsOpen = false;
        }

        private void OnSearchBarExecuted(ItemClickEventArgs e)
        {
            this.SearchQuery = string.Empty;
            this.NavigationBarIsOpen = false;
            this.SearchBarIsOpen = true;
        }

        private void OnAirDayExecuted(ItemClickEventArgs e)
        {
            base.NavigationService.Navigate<AirViewModel>(-1);
        }

        private bool OnAirDayCanExecute(ItemClickEventArgs e)
        {
            return this.Model.AirDay.Any();
        }

        private void OnAirWeekExecuted(ItemClickEventArgs e)
        {
            base.NavigationService.Navigate<AirViewModel>(-2);
        }

        private bool OnAirWeekCanExecute(ItemClickEventArgs e)
        {
            return this.Model.AirWeek.Any();
        }

        private void OnAirMonthExecuted(ItemClickEventArgs e)
        {
            base.NavigationService.Navigate<AirViewModel>(-3);
        }

        private bool OnAirMonthCanExecute(ItemClickEventArgs e)
        {
            return this.Model.AirMonth.Any();
        }

        private void OnAirYearExecuted(ItemClickEventArgs e)
        {
            base.NavigationService.Navigate<AirViewModel>(-4);
        }

        private bool OnAirYearCanExecute(ItemClickEventArgs e)
        {
            return this.Model.AirYear.Any();
        }

        #endregion

        private void Model_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case "AirDay":
                    this.AirDayCommand.NotifyCanExecuteChanged();
                    break;
                case "AirWeek":
                    this.AirWeekCommand.NotifyCanExecuteChanged();
                    break;
                case "AirMonth":
                    this.AirMonthCommand.NotifyCanExecuteChanged();
                    break;
                case "AirYear":
                    this.AirYearCommand.NotifyCanExecuteChanged();
                    break;
            }
        }

        private async void SwitchState(FrameState state)
        {
            this.state = state;
            switch (this.state)
            {
                case FrameState.Entrance:
                    this.NavigationBarCanOpen = true;
                    this.Background = null;
                    break;
                case FrameState.Series:
                    this.NavigationBarCanOpen = true;
                    await AppX.Instance.Current.FanArt.DownloadImage();
                    this.Background = AppX.Instance.Current.FanArt.LocalPath;
                    break;
            }
        }

        private enum FrameState
        {
            Entrance,
            Series
        }

        public async void OnShareRequested(DataRequest request)
        {
            if ((this.Model.Current == null || string.IsNullOrWhiteSpace(this.Model.Current.ImdbID) || this.state != FrameState.Series))
            {
                return;
            }

            var deferal = request.GetDeferral();

            request.Data.SetWebLink(new Uri("http://www.imdb.com/title/" + this.Model.Current.ImdbID));
            request.Data.Properties.Title = this.Model.Current.Name;
            request.Data.Properties.Description = this.Model.Current.Overview;
            request.Data.SetText(this.Model.Current.Overview);

            try
            {
                var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(this.Model.Current.FanArt.LocalPath));

                var fanArtRef = RandomAccessStreamReference.CreateFromFile(file);
                request.Data.SetBitmap(fanArtRef);

                var thumb = await file.GetThumbnailAsync(Windows.Storage.FileProperties.ThumbnailMode.PicturesView, 240, Windows.Storage.FileProperties.ThumbnailOptions.ResizeThumbnail);
                request.Data.Properties.Thumbnail = RandomAccessStreamReference.CreateFromStream(thumb);
            }
            catch (FileNotFoundException) { }
            finally { deferal.Complete(); }
        }

        public ISharingService SharingService
        {
            set;
            private get;
        }

        public ISettingService SettingService
        {
            set;
            private get;
        }
    }
}